-----------------------------------------------------------------------------
--
-- Module      :  Examle
-- Copyright   :
-- License     :  AllRightsReserved
--
-- Maintainer  :  Eduard Sergeev
-- Stability   :  Highly Experimental
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

{-# LANGUAGE TemplateHaskell, TypeFamilies, NoImplicitPrelude, QuasiQuotes,
TypeOperators, FlexibleContexts, RankNTypes, FlexibleInstances, MultiParamTypeClasses #-}

module Data.Unit.Example where

import Data.Function
import Prelude (Fractional, Double, Int, print, undefined)
import qualified Prelude as P
import Data.Unit.Types
import Data.Unit.Instances
import Data.Unit.Metric
import Data.Unit.Generator


--fromInteger :: P.Integer -> UMNumber m a
--fromInteger = UMNumber . P.fromInteger
--fromRational = UMNumber

--type family a :*: b

g = metres 9.8 / seconds 1 / seconds 1   -- show g ==> 9.8<m/s^2>

g' = unify 9.8 :: Double :<: (M :/: (S :*: S))

g'' = Un 9.8 :: Double :<: (M :/: (S :*: S))

type V = M :/: S

type Uni n m = n :<: m

v1 :: Double :<: V
v1 = g * seconds 5                        -- show v1 ==> 49.0<m/s>

s1 = v1 * seconds 3                      -- show s1 ==> 147.0<m>

--ferr = v1 + s1                          -- error!

dv = v1 - g * seconds 2                  -- show dv ==> 29.4<m/s>

type VS = (Divide V S r) => r

gg = undefined :: VS

--a2 :: Double :<: VS
a2 = v1 / seconds 1

-- | Custom unit
$(um "ft" "feet" "6") 


heightOfMyOfficeWindow = feet 32.2  

feetPerMetre = feet 3.28084 / metres 1

heightOfMyOfficeWindowInMetres = heightOfMyOfficeWindow / feetPerMetre  -- ==> 9.814559685934091<m>

--
--sqrSpeed1 x = let x' = x+(metres 0/seconds 1) in x'*x'
sqrSpeed1 x = let g = (x+(metres 0/seconds 1)) in g*g

--sqrSpeed2 :: UMNumber (M :/: S) Double -> UMNumber (M :*: M :/: S :*: S) Double
--sqrSpeed2 :: UFractional u n => u (M :/: S) n -> u (M :*: M :/: S :*: S) n
--sqrSpeed2 :: UNum u n => u (M :/: S) n -> u (M :*: M :/: S :*: S) n
sqrSpeed2 x = x*x

--sp3 :: UNum u n => u Sp n -> u (((M :*: M) :/: S) :/: S) n
--sp3 = undefined
--type JJ = UNum u n => u [measure|M/S|] n -> u [measure|((M*M)/(S*S))] n 

hh x = undefined -- [measure| g |]

--type Sp = [measure|M/S|]

--type Sp = Divide M S r => r

type family KK
type instance KK = S :/: M

$(um "C" "celcius" "8")     -- temperature, Celsius/Centigrade
$(um "F" "fahrenheit" "9")  -- temperature, Fahrenheit

convertCtoF :: Double :<: C -> Double :<: F
convertCtoF temp = fahrenheit 9.0 / celcius 5.0 * temp + fahrenheit 32.0

convertFtoC temp = celcius 5.0 / fahrenheit 9.0 * (temp - fahrenheit 32.0)

f1 = convertCtoF (celcius 36.6)      --  show f1 ==> 97.88000000000001<F>
c1 = convertFtoC (fahrenheit 451)    --  show c1 ==> 232.7777777777778<C>

tt1 = f1 * f1
tt2 = tt1 * tt1
tt3 = tt2 * tt2
tt4 = tt3 * tt3
--tt5 = tt4 * tt4
--tt6 = tt5 * tt5

--main = do
--    print (seconds 1 * metres 6 * seconds 7)


--type a ://: b = (Divide a b r) => r 

--tr :: (UNum u n, Multiply M S ms, Divide ms M r) => u r n -> u r n
--tr n = n + n

--tr2 :: (UNum u n, Multiply M S ms) => u (ms ://: M) n -> u (ms :/: M) n
--tr2 n = n + n